using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Caching.Memory;
using Xunit;
using MT5Trade.Models;
using MT5Trade.Models.MarketData;

namespace MT5Trade.Tests.TestFramework
{
    /// <summary>
    /// 真实数据测试基类
    /// </summary>
    public abstract class RealDataTestBase : IAsyncLifetime
    {
        protected IServiceProvider ServiceProvider { get; private set; }
        protected IMarketDataProvider DataProvider { get; private set; }
        protected IConfiguration Configuration { get; private set; }
        protected RealExposureCalculator ExposureCalculator { get; private set; }
        protected decimal TestAccountBalance { get; private set; } = 100000m;

        /// <summary>
        /// 初始化测试环境
        /// </summary>
        public async Task InitializeAsync()
        {
            var services = new ServiceCollection();

            // 配置
            Configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.test.json", optional: true)
                .AddInMemoryCollection(new Dictionary<string, string>
                {
                    ["MarketData:Provider"] = "YahooFinance",
                    ["MarketData:CacheEnabled"] = "true",
                    ["MarketData:CacheDuration"] = "01:00:00",
                    ["TestSettings:UseRealData"] = "true",
                    ["TestSettings:DataLookbackDays"] = "30",
                    ["TestSettings:TestAccountBalance"] = "100000"
                })
                .Build();

            // 注册服务
            services.AddSingleton(Configuration);
            services.AddMemoryCache();
            services.AddHttpClient();
            services.AddLogging(builder =>
            {
                builder.AddConsole();
                builder.SetMinimumLevel(LogLevel.Warning);
            });

            // 注册市场数据服务
            services.AddSingleton<IMarketDataProvider, YahooFinanceDataProvider>();
            services.AddSingleton<RealExposureCalculator>();
            services.AddSingleton<GapHedgingStrategy>();

            ServiceProvider = services.BuildServiceProvider();
            DataProvider = ServiceProvider.GetRequiredService<IMarketDataProvider>();
            ExposureCalculator = ServiceProvider.GetRequiredService<RealExposureCalculator>();

            // 初始化测试账户余额
            TestAccountBalance = Configuration.GetValue<decimal>("TestSettings:TestAccountBalance");

            // 预热缓存
            await WarmupCacheAsync();
        }

        /// <summary>
        /// 清理测试环境
        /// </summary>
        public Task DisposeAsync()
        {
            if (ServiceProvider is IDisposable disposable)
            {
                disposable.Dispose();
            }
            return Task.CompletedTask;
        }

        /// <summary>
        /// 预热缓存
        /// </summary>
        protected virtual async Task WarmupCacheAsync()
        {
            // 预加载常用品种的数据
            var commonSymbols = new[] { "EURUSD=X", "GBPUSD=X", "SPY" };
            foreach (var symbol in commonSymbols)
            {
                try
                {
                    await DataProvider.GetLatestQuoteAsync(symbol);
                }
                catch
                {
                    // 忽略预热错误
                }
            }
        }

        /// <summary>
        /// 加载真实市场场景
        /// </summary>
        protected async Task<MarketScenario> LoadRealMarketScenarioAsync(
            string symbol,
            DateTime testDate,
            int lookbackDays = 30)
        {
            var endDate = testDate;
            var startDate = testDate.AddDays(-lookbackDays);

            // 加载历史数据
            var historicalData = await DataProvider.GetHistoricalDataAsync(
                symbol, startDate, endDate);

            if (historicalData == null || !historicalData.Any())
            {
                throw new InvalidOperationException($"无法获取{symbol}的历史数据");
            }

            // 识别缺口
            var gaps = await DataProvider.IdentifyGapsAsync(
                symbol, startDate, endDate, 0.005); // 0.5%以上的缺口

            // 计算波动率
            var volatility = await DataProvider.CalculateVolatilityAsync(symbol, 20);

            // 获取相关性矩阵
            var correlations = await GetCorrelationMatrixAsync(symbol);

            // 计算统计信息
            var returns = CalculateReturns(historicalData);
            var stats = CalculateStatistics(returns);

            return new MarketScenario
            {
                Symbol = symbol,
                StartDate = startDate,
                EndDate = endDate,
                MarketData = historicalData,
                IdentifiedGaps = gaps,
                Volatility = volatility,
                CorrelationMatrix = correlations,
                MarketRegime = await DetermineMarketRegimeAsync(symbol, volatility, historicalData),
                AverageReturn = stats.mean,
                Skewness = stats.skewness,
                Kurtosis = stats.kurtosis,
                TradingDays = historicalData.Count
            };
        }

        /// <summary>
        /// 获取相关性矩阵
        /// </summary>
        protected async Task<Dictionary<string, double>> GetCorrelationMatrixAsync(string symbol)
        {
            // 获取相关品种
            var relatedSymbols = GetRelatedSymbols(symbol);

            if (relatedSymbols.Count < 2)
            {
                return new Dictionary<string, double> { { $"{symbol}_{symbol}", 1.0 } };
            }

            return await DataProvider.CalculateCorrelationMatrixAsync(relatedSymbols, 30);
        }

        /// <summary>
        /// 获取相关品种
        /// </summary>
        protected List<string> GetRelatedSymbols(string symbol)
        {
            // 外汇对
            if (symbol.Contains("USD"))
            {
                return new List<string> { "EURUSD=X", "GBPUSD=X", "USDJPY=X" }
                    .Where(s => s != symbol).Take(2).Prepend(symbol).ToList();
            }

            // 股票指数
            if (symbol == "SPY" || symbol == "QQQ" || symbol == "DIA")
            {
                return new List<string> { "SPY", "QQQ", "DIA" }
                    .Where(s => s != symbol).Take(2).Prepend(symbol).ToList();
            }

            // 默认返回单个品种
            return new List<string> { symbol };
        }

        /// <summary>
        /// 确定市场状态
        /// </summary>
        protected async Task<MarketRegime> DetermineMarketRegimeAsync(
            string symbol,
            MarketVolatility volatility,
            List<MarketTick> data)
        {
            // 基于波动率和价格模式判断市场状态
            if (volatility.Annualized > 0.4)
                return MarketRegime.Crisis;

            if (volatility.Annualized > 0.25)
                return MarketRegime.Volatile;

            // 分析趋势
            var trend = AnalyzeTrend(data);
            if (Math.Abs(trend.Slope) > 0.001)
                return MarketRegime.Trending;

            return MarketRegime.RangeBound;
        }

        /// <summary>
        /// 分析趋势
        /// </summary>
        protected TrendAnalysis AnalyzeTrend(List<MarketTick> data)
        {
            if (data == null || data.Count < 2)
            {
                return new TrendAnalysis { Slope = 0, R2 = 0, Direction = TrendDirection.Neutral };
            }

            var prices = data.Select(d => (double)d.Close).ToList();
            var (slope, r2) = CalculateLinearRegression(prices);

            var direction = slope > 0.001 ? TrendDirection.Up :
                          slope < -0.001 ? TrendDirection.Down :
                          TrendDirection.Neutral;

            return new TrendAnalysis
            {
                Slope = slope,
                R2 = r2,
                Direction = direction
            };
        }

        /// <summary>
        /// 计算线性回归
        /// </summary>
        protected (double slope, double r2) CalculateLinearRegression(List<double> prices)
        {
            var n = prices.Count;
            if (n < 2) return (0, 0);

            var xSum = 0.0;
            var ySum = 0.0;
            var xySum = 0.0;
            var x2Sum = 0.0;
            var y2Sum = 0.0;

            for (int i = 0; i < n; i++)
            {
                xSum += i;
                ySum += prices[i];
                xySum += i * prices[i];
                x2Sum += i * i;
                y2Sum += prices[i] * prices[i];
            }

            var denominator = n * x2Sum - xSum * xSum;
            if (denominator == 0) return (0, 0);

            var slope = (n * xySum - xSum * ySum) / denominator;
            var intercept = (ySum - slope * xSum) / n;

            // 计算R²
            var yMean = ySum / n;
            var ssTot = prices.Sum(y => Math.Pow(y - yMean, 2));
            var ssRes = prices.Select((y, i) => Math.Pow(y - (slope * i + intercept), 2)).Sum();

            var r2 = ssTot == 0 ? 0 : 1 - (ssRes / ssTot);

            return (slope, r2);
        }

        /// <summary>
        /// 计算收益率
        /// </summary>
        protected List<double> CalculateReturns(List<MarketTick> data)
        {
            var returns = new List<double>();
            for (int i = 1; i < data.Count; i++)
            {
                var dailyReturn = (double)((data[i].Close - data[i - 1].Close) / data[i - 1].Close);
                returns.Add(dailyReturn);
            }
            return returns;
        }

        /// <summary>
        /// 计算统计信息
        /// </summary>
        protected (double mean, double skewness, double kurtosis) CalculateStatistics(List<double> returns)
        {
            if (!returns.Any()) return (0, 0, 0);

            var mean = returns.Average();
            var n = returns.Count;

            // 计算方差
            var variance = returns.Sum(r => Math.Pow(r - mean, 2)) / n;
            var stdDev = Math.Sqrt(variance);

            if (stdDev == 0) return (mean, 0, 0);

            // 计算偏度
            var skewness = returns.Sum(r => Math.Pow((r - mean) / stdDev, 3)) / n;

            // 计算峰度
            var kurtosis = returns.Sum(r => Math.Pow((r - mean) / stdDev, 4)) / n - 3;

            return (mean, skewness, kurtosis);
        }

        /// <summary>
        /// 生成测试持仓
        /// </summary>
        protected List<Position> GenerateTestPositions(string symbol, decimal currentPrice)
        {
            // 基于账户余额生成合理的持仓
            var positionValue = TestAccountBalance * 0.1m; // 每个持仓占10%
            var contractSize = GetContractSize(symbol);
            var volume = (double)(positionValue / (currentPrice * contractSize));

            return new List<Position>
            {
                new Position
                {
                    Symbol = symbol,
                    Volume = Math.Round(volume, 2),
                    Type = PositionType.Long,
                    EntryPrice = currentPrice * 0.99m, // 假设以更低价格入场
                    OpenTime = DateTime.Now.AddDays(-5),
                    ContractSize = contractSize,
                    Margin = positionValue * 0.1m // 10倍杠杆
                }
            };
        }

        /// <summary>
        /// 获取合约大小
        /// </summary>
        protected decimal GetContractSize(string symbol)
        {
            // 外汇标准合约
            if (symbol.Contains("USD") || symbol.Contains("EUR") ||
                symbol.Contains("GBP") || symbol.Contains("JPY"))
            {
                return 100000; // 标准手
            }

            // 股票和ETF
            return 1;
        }

        /// <summary>
        /// 模拟对冲执行
        /// </summary>
        protected HedgeExecutionResult SimulateHedgeExecution(
            MarketAdaptiveHedgeParams hedgeParams,
            MarketTick currentTick,
            MarketVolatility volatility)
        {
            // 模拟滑点
            var slippage = currentTick.Close * (decimal)(volatility.Daily * 0.1);
            var executedPrice = currentTick.Close + slippage;

            // 模拟交易成本
            var transactionCost = executedPrice * 0.001m; // 0.1%

            return new HedgeExecutionResult
            {
                ExecutionTime = currentTick.Time,
                HedgeParams = hedgeParams,
                ExecutedPrice = executedPrice,
                Slippage = slippage,
                IsSuccessful = true,
                TransactionCost = transactionCost,
                HedgeEffectiveness = hedgeParams.HedgeRatio * 0.8 // 假设80%的理论有效性
            };
        }

        /// <summary>
        /// 验证策略表现
        /// </summary>
        protected async Task ValidateStrategyPerformanceAsync(
            List<HedgeExecutionResult> results,
            MarketScenario scenario)
        {
            if (!results.Any())
            {
                Assert.True(scenario.IdentifiedGaps.Count == 0,
                    "存在缺口但策略未执行对冲");
                return;
            }

            // 验证缺口识别准确性
            var actualGaps = scenario.IdentifiedGaps.Count;
            var executedHedges = results.Count;
            var accuracyRatio = actualGaps > 0 ? (double)executedHedges / actualGaps : 1.0;

            Assert.True(accuracyRatio >= 0.7,
                $"缺口识别准确率过低: {accuracyRatio:P0}");

            // 验证对冲有效性
            var avgEffectiveness = results.Average(r => r.HedgeEffectiveness);
            Assert.True(avgEffectiveness >= 0.6,
                $"对冲有效性不足: {avgEffectiveness:P0}");

            // 验证成本控制
            var totalCost = results.Sum(r => r.TransactionCost);
            var costRatio = totalCost / TestAccountBalance;
            Assert.True(costRatio <= 0.02m,
                $"交易成本过高: {costRatio:P2}");

            // 验证执行成功率
            var successRate = results.Count(r => r.IsSuccessful) / (double)results.Count;
            Assert.True(successRate >= 0.95,
                $"执行成功率过低: {successRate:P0}");
        }
    }

    /// <summary>
    /// 趋势分析结果
    /// </summary>
    public class TrendAnalysis
    {
        public double Slope { get; set; }
        public double R2 { get; set; }
        public TrendDirection Direction { get; set; }
    }

    /// <summary>
    /// 趋势方向
    /// </summary>
    public enum TrendDirection
    {
        Up,
        Down,
        Neutral
    }
}